package com.me.extend.view

import android.os.Build.VERSION.SDK_INT
import android.view.View
import com.me.extend.thread.isMainThread
import java.util.concurrent.atomic.AtomicInteger

/**
 * 1、生成不与AAPT生成的ID相冲突的View ID（ R.id.xxx ），比在主线程上调用的View.generateViewId更有效。
 * 2、将其分配给视图。
 * 3、禁用实例状态保存以提高效率。 因为状态无法还原到其ID在活动重新启动期间发生变化的视图中。
 * 4、返回生成的ID
 */
fun View.assignAndGetGeneratedId(): Int = generateViewId().also { generatedId ->
    id = generatedId
    isSaveEnabled = false // New id will be generated, so can't restore saved state.
}

/**
 * 如果此View具有有效的ID（不同于0 / View.NO_ID ），则将其返回。
 * 否则，调用AssignAndGetGeneratedId ，并返回新的分配ID。
 */
val View.existingOrNewId: Int
    get() = id.let { currentId ->
        if (currentId == View.NO_ID) assignAndGetGeneratedId() else currentId
    }

/**
 * 生成与AAPT生成的视图ID（ R.id.xxx ）不冲突的View ID。
 * 针对主线程的使用进行了特别优化，使其免于同步。 API 17以下向后兼容
 */
fun generateViewId(): Int = when {
    isMainThread -> mainThreadLastGeneratedId.also {
        // 在此减小，以避免与递增的其他生成的id发生任何冲突。
        mainThreadLastGeneratedId = (if (it == 1) aaptIdsStart else it) - 1
    }
    SDK_INT >= 17 -> View.generateViewId()
    else -> generatedViewIdCompat()
}

/** aapt-generated IDs have the high byte nonzero. Clamp to the range under that. */
private const val aaptIdsStart = 0x00FFFFFF
private var mainThreadLastGeneratedId = aaptIdsStart - 1

private val nextGeneratedId = AtomicInteger(1)
private fun generatedViewIdCompat(): Int {
    while (true) {
        val result = nextGeneratedId.get()
        // aapt-generated IDs have the high byte nonzero. Clamp to the range under that.
        var newValue = result + 1
        if (newValue > aaptIdsStart) newValue = 1 // Roll over to 1, not 0.
        if (nextGeneratedId.compareAndSet(result, newValue)) {
            return result
        }
    }
}
